<template>
    <div class="my-input-components">
        <input
            :class="inputClasses"
            :maxlength="maxlength"
            class="input-dropdown ivu-input"
            ref="inputDropdown"
            type="text"
            :disabled="disabled"
            :placeholder="placeholder"
            v-model="keywork"
            @focus="handleFocus"
            @blur="handleBlur"
            @keydown.down.prevent="navigateOptions('next')"
            @keydown.up.prevent="navigateOptions('prev')"
            @keyup.enter="handleKeyupEnter"
            autocomplete="off"
        />
        <transition name="transition-drop">
            <div class="result-list" ref="dropdown">
                <ul class="input-dropdown-ul" v-if="isFocus && options.length">
                    <li
                        v-for="(item, index) in options"
                        :key="item[valueKey]"
                        :class="{
                            'input-dropdown-item': true,
                            'input-dropdown-selected': value === item[valueKey],
                            'input-dropdown-hover': hoverIndex === index,
                        }"
                        @click="handleClick(item, index)"
                    >{{item | getOptionLables(displayField)}}</li>
                </ul>
            </div>
        </transition>
    </div>
</template>
<script>
import '@/view/components/RemoteSearch/myInputComponents.less'
import Popper from 'popper.js'
import { trim, debounce } from '@/libs/tools'
/**
 * 获取下拉选项展示的内容
 * @param {Object} data 下拉选项的值
 * @param {Array} keys 需要展示的keys数组集合
 * @param {String} flag 分割符号
 * @returns {String}
 */
function getOptionLables (data, keys, flag = ' ') {
    return keys
        .map(key => {
            return data[key] || ''
        })
        .join(flag)
}
export default {
    props: {
        value: {
            default: ''
        },
        valueKey: {
            default: 'value',
            type: String
        },
        labelKey: {
            default: 'label',
            type: String
        },
        // 显示字段
        displayField: {
            default: () => ['label'],
            type: Array
        },
        // 大小
        size: {
            validator (value) {
                return ['small', 'large', 'default'].indexOf(value) > -1
            },
            default: 'default'
        },
        // 输入提示
        placeholder: {
            type: String,
            default: ''
        },
        // 是否禁用
        disabled: {
            type: Boolean,
            default: false
        },
        // 最大输入长度
        maxlength: {
            type: [Number, String],
            default: ''
        },
        // 默认展示的下拉选项
        defaultOptions: {
            type: Array,
            default: () => []
        },
        // 远程搜索方法 返回promise
        remoteMethod: {
            type: Function,
            default: () => {
                return Promise.resolve([])
            }
        },
        // change 时 是否返回一个带有label的对象
        'label-in-value': {
            type: Boolean,
            default: false
        },
        // 下拉选项位置
        placement: {
            type: String,
            default: 'bottom-start'
        }
    },
    data () {
        return {
            isFocus: false,
            hoverIndex: -1,
            keywork: '',
            options: []
        }
    },
    computed: {
        inputClasses () {
            return [`ivu-input-${this.size}`]
        }
    },
    watch: {
        // 输入的搜索内容改变
        keywork (value) {
            const v = trim(value)
            if (v) {
                // 判断是否有 上下移动选择中的选项
                // 判断选中的选项是否和搜索的内容相关 如果不相关则清空已选择的选项
                const hoverOption = this.options[this.hoverIndex]
                const label = hoverOption && hoverOption[this.labelKey] || ''
                if (!hoverOption ||
                    !getOptionLables(hoverOption, this.displayField, ',')
                        .toUpperCase()
                        .includes(v.toUpperCase())
                ) {
                    this.hoverIndex = -1
                }

                // 远程搜索内容
                this.handleRemoteSearch(v, () => {
                    // 设置上下移动的光标位置
                    this.hoverIndex = label
                        ? this.options.findIndex(item => {
                            return item[this.labelKey] === label
                        })
                        : -1
                })
            } else {
                // 为空 则清空输入的内容
                this.hoverIndex = -1
                this.$emit('input', '')
                this.$emit('change', null)
                this.options = this.defaultOptions.slice()
            }
        },
        isFocus (v) {
            if (v) {
                this.updatePopper()
            } else {
                this.$emit('get-query-name', this.keywork)
                this.destroyPopper()
            }
        },
        // 设置滚动条
        hoverIndex (index) {
            if (index < 0) return
            // update scroll
            const label = this.options[index][this.labelKey]
            const ulEle = this.$refs.dropdown
            const optionInstance = Array
                .from(ulEle.getElementsByClassName('input-dropdown-item'))
                .find(node => node.innerText.includes(label))
            if (optionInstance) {
                let bottomOverflowDistance = optionInstance.getBoundingClientRect().bottom - ulEle.getBoundingClientRect().bottom
                let topOverflowDistance = optionInstance.getBoundingClientRect().top - ulEle.getBoundingClientRect().top
                if (bottomOverflowDistance > 0) {
                    ulEle.scrollTop += bottomOverflowDistance
                }
                if (topOverflowDistance < 0) {
                    ulEle.scrollTop += topOverflowDistance
                }
            }
        }
    },
    created () {
        this.options = this.defaultOptions.slice(0, 15)
    },
    methods: {
        // 选项上下移动
        navigateOptions (direction) {
            if (direction === 'next') {
                this.hoverIndex++
                if (this.hoverIndex >= this.options.length) {
                    this.hoverIndex = 0
                }
            } else if (direction === 'prev') {
                this.hoverIndex--
                if (this.hoverIndex < 0) {
                    this.hoverIndex = this.options.length - 1
                }
            }
        },

        // 处理回车事件
        handleKeyupEnter (event) {
            const v = trim(event.target.value)
            const hoverOption = this.hoverIndex > -1 && this.options[this.hoverIndex] || ''
            if (hoverOption) {
                // 如果存在 选项 则直接选中 （输入的搜索内容改变时判断过是否清空）
                this.handleClick(hoverOption, this.hoverIndex)
            } else {
                // 判断搜索的内容是否在选项列表中
                const value = v.toUpperCase()
                const index = this.options.findIndex(item => {
                    return getOptionLables(item, this.displayField, ',')
                        .toUpperCase()
                        .includes(value)
                })
                // 存在则选中第一个 不存在则重新搜索
                if (index < 0) {
                    this.handleRemoteSearch(v, (list) => {
                        this.hoverIndex = -1
                        if (list.length) {
                            // 默认选上第一个
                            this.handleClick(list[0], 0)
                        } else {
                            // 没有则清空
                            this.$emit('input', '')
                            this.$emit('change', null)
                        }
                    })
                } else {
                    this.handleClick(this.options[index], index)
                }
            }
            this.$nextTick(() => {
                this.$refs.inputDropdown.blur()
            })
        },

        /**
         * 处理点击选项事件
         * @param {Object} option
         * @param {Number} index
         */
        handleClick (option, index) {
            this.hoverIndex = index
            this.$emit('input', this.options[index][this.valueKey])
            this.$emit('change', this['label-in-value'] ? option : this.value)
            this.keywork = this.options[index][this.labelKey]
            this.$nextTick(() => {
                this.$refs.inputDropdown.blur()
            })
        },

        /**
         * 处理input  focus 事件
         */
        handleFocus (event) {
            this.$emit('on-focus', event)
            this.$nextTick(() => {
                this.isFocus = true
            })
        },

        /**
         * 处理 input blur  事件
         */
        handleBlur (event) {
            this.$emit('on-blur', false)
            this.$nextTick(() => {
                this.isFocus = false
            })
        },

        /**
         * 处理远程搜索事件
         */
        handleRemoteSearch: debounce(function (v, cb) {
            this.remoteMethod(v).then(data => {
                const list = data && data.length ? data : []
                this.options = list
                cb && cb(list)
            })
        }, 200),
        resetTransformOrigin () {
            if (!this.popper) return
            let x_placement = this.popper.popper.getAttribute('x-placement')
            let placementStart = x_placement.split('-')[0]
            let placementEnd = x_placement.split('-')[1]
            const leftOrRight = x_placement === 'left' || x_placement === 'right'
            if (!leftOrRight) {
                this.popper.popper.style.transformOrigin = placementStart === 'bottom' || (placementStart !== 'top' && placementEnd === 'start') ? 'center top' : 'center bottom'
            }
        },
        // 更新 Popper 插件
        updatePopper () {
            if (this.popper) {
                this.$nextTick(() => {
                    this.popper.update()
                })
            } else {
                this.$nextTick(() => {
                    this.popper = new Popper(this.$refs.inputDropdown, this.$refs.dropdown, {
                        placement: this.placement,
                        modifiers: {
                            computeStyle: {
                                gpuAcceleration: false
                            },
                            preventOverflow: {
                                boundariesElement: 'window'
                            }
                        },
                        onCreate: () => {
                            this.resetTransformOrigin()
                            this.$nextTick(this.popper.update())
                        },
                        onUpdate: () => {
                            this.resetTransformOrigin()
                        }
                    })
                })
            }
        },
        // 删除 Popper 插件
        destroyPopper () {
            if (this.popper) {
                this.$nextTick(() => {
                    this.popper.destroy()
                    this.popper = null
                })
            }
        }
    },
    filters: {
        getOptionLables
    },
    beforeDestroy () {
        if (this.popper) {
            this.popper.destroy()
        }
    }
}
</script>
